home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1995 April / Internet Tools.iso / mail / sendmail / IDA / sendmail-tutorial.txt.Z / sendmail-tutorial.txt
Encoding:
Internet Message Format  |  1993-07-07  |  15.9 KB

  1. From: Eliot Lear <lear@NET.BIO.NET>
  2.  
  3. The following was written by Dr. Charles Hedrick of Rutgers University
  4. sometime in 1985.  Please read it with the understanding that rule 
  5. numbers are nothing more than function names.  For further reference,
  6. I suggest the Sun Tutorial on Sendmail in their manuals.
  7. -eliot
  8.  
  9. Command: followup
  10. Newsgroups: net.unix-wizards,net.mail
  11. To: steve@jplgodo.UUCP
  12. Subject: a brief tutorial on sendmail rules
  13. Distribution: 
  14. References: <902@rlgvax.UUCP> <545@jplgodo.UUCP>
  15.  
  16. A previous message suggested using "sendmail -bt" to see how sendmail
  17. is going to process an address.  This is indeed a handy command for
  18. testing how an address will be processed.  However the instructions
  19. given were not quite right.  To see how sendmail is going to deliver
  20. mail to a given address, a reasonable thing to type is
  21.     sendmail -bt
  22.     0,4 address
  23. Even this isn't quite right, but with "normal" rule sets it should work.
  24.  
  25. Because there is so much confusion about sendmail rules, the rest of
  26. this message contains a brief tutorial.  My own opinion of sendmail is
  27. that it is quite a good piece of work.  Many people have complained
  28. about the difficulty of understanding sendmail rule sets.  However I
  29. have also worked with mailers that code address processing directly
  30. into the program.  I much prefer sendmail.  The real problem is not
  31. with sendmail, but with the rules.  The rules normally shipped from
  32. Berkeley have lots of code that does strange Berkeley-specific things,
  33. and they are not commented.  Also, typical complex rule sets are
  34. trying to handle lots of things, forwarding mail among several
  35. different mail systems with incompatible addressing conventions.  A
  36. rule set to handle just old-style (non-domain) UUCP mail would be very
  37. simple and easy to understand.  But real rule sets are not doing
  38. simple things, so they are not simple.
  39.  
  40. For those not familiar with sendmail, -bt invokes the rule tester.  It
  41. lets you type a set of rule numbers and an address, and then shows you
  42. what the rules will do to that address.  In addition, rule test mode
  43. automatically applies rule 3 before whatever rule you ask it to apply.
  44. As we will see shortly, this is a reasonable thing to do.
  45.  
  46. Before describing the rule sets, let me define two terms: "header" and
  47. "envelope".  Header refers to the lines at the beginning of the
  48. message, starting with "from:", "to:", "subject:", etc.  Sendmail does
  49. process these lines.  E.g. with uucp mail it will add its own host
  50. name at the beginning of the from line, so that the final recipient
  51. stands some change of replying to the message.  However sendmail
  52. normally does not depend upon the from and to lines to perform its
  53. actual delivery.  It has more direct knowledge, passed on to it from
  54. the program that generated the mail, or if it came from another site,
  55. the mailer at that site.  This information is referred to as the
  56. "envelope", since it is like the addresses on the outside of an
  57. envelope.  For Arpanet mail, the envelope is passed to the next site
  58. by the MAIL FROM: and RCPT TO: commands.  For UUCP mail, it is passed
  59. on as arguments to the remote rmail command.  To see why there have to
  60. be separate addresses "on the envelope", consider what happens when
  61. you send mail to "john@vax, mary@sun".  Two copies of the message will
  62. be dispatched, one to vax and the other to sun.  The "to: " line in
  63. the headers will show both addresses.  However the envelope will show
  64. only the right address that we want this copy to go to.  The copy sent
  65. to vax will show "john@vax" and the copy sent to sun will show
  66. "mary@sun".  If sendmail had to look at the "to: " line, it would
  67. never know which of the addresses shown there it was responsible for
  68. handling.
  69.  
  70. Anyway, here is what the rules do:
  71.  
  72. 3: always done first.  This turns addresses from their normal textual
  73. form into a form that the rest of the rules understand.  In most
  74. cases, all it does it put < > around the name of the host that is next
  75. in line.  Thus foo@bar turns into foo<@bar>.  However it also does a
  76. few transformations.  E.g. it turns foo!bar!user into
  77. bar!user<@foo.UUCP>.  Since sendmail accepts either ! syntax or
  78. @....UUCP syntax, rule 3 standardizes on @ syntax.  It also does a few
  79. other minor things.  But you won't be far off if you just think of it
  80. as adding < > around the host name.
  81.  
  82. 4: always done last.  This turns addresses from internal form  back
  83. into external form.  It removes the < > around the host name, and
  84. turns foo@bar.UUCP back into bar!foo.  Again, there are one or two
  85. other minor things, but you won't be too far off if you think of 4 as
  86. just removing the < > around the host name.
  87.  
  88. 0: This is the rule that handles the destination address on the
  89. envelope.  It is in some sense the primary rule.  It returns a triple:
  90. protocol, host, user.  The protocol is usually one of local, TCP, or
  91. UUCP.  At the moment, it figures this out syntactically.  In our rule
  92. set, hosts ending in .UUCP are handled by UUCP, the current host is
  93. local, and everything else is TCP.  As domains are integrated into
  94. UUCP, obviously this rule is going to change.  This rule does very
  95. little other than simply look at the format of the host name, though
  96. as usual a few other details are involved (e.g. it removes the local
  97. host.  So myhost!foo!bar will be sent directly to foo).
  98.  
  99. 1 and 2 are protocol-independent transformations used for sender and
  100. recipient lines in the header (i.e. from: and to: lines).  In our
  101. rule sets, they don't do anything.
  102.  
  103. Each protocol has its own rules to use for sender and recipient lines
  104. in the header.  E.g. UUCP rules might add the local host name to the
  105. beginning of the from line and remove it from the to line.  In our
  106. rule set, the complexities in these rules are primarily caused by
  107. forwarding between UUCP and TCP.  The line that defines the mailer for
  108. a protocol lists the rule to use for source and recipient, in the S=
  109. and R=.
  110.  
  111. Finally, here is the exact sequence in which these rules are used.
  112. For example, the first line means that the destination specified in
  113. the envelope is processed first by rule 3, then rule 0, then rule 4.
  114.  
  115. envelope recipient:    3,0,4  [actually rule 4 is applied only to the
  116.                 user name portion of what rule 0 returns]
  117. envelope sender:       3,1,4
  118. header recipient:      3,2,xx,4  [xx is the rule number specified in R=]
  119. header sender:         3,1,xx,4  [xx is the rule number specified in S=]
  120.  
  121. I have the impression that the sender from the envelope (the
  122. return-path) may actually get processed twice, once by 3,1,4 and the
  123. second time by 3,1,xx,4.  However I'm not sure about that.
  124.  
  125. Now for the format of the rules themselves.  I'm just going to show
  126. some examples, since sendmail comes with a reference manual, which you
  127. can refer to.  However these examples are probably enough to let you
  128. understand any set of rules that makes sense in the first place (which
  129. the normal rules do not).  This example is from our UUCP definition.
  130. It a simplified version of the set of rules used to process the sender
  131. specification.  As such, the major thing it has to do is to add our
  132. host name to the beginning, so that the guy at the end will know that
  133. the mail went through us.
  134.  
  135. S13
  136. R$+<@$-.UUCP>        $2!$1                u@host.UUCP => host!u
  137. R$=U!$+            $2                strip local name
  138. R$+            $:$U!$1                stick on our host name
  139.  
  140. Briefly, the first rule turns the address from the form foo<@bar.UUCP>
  141. back into bar!foo.  The second rule removes our local host name, if
  142. it happens to be there already, so we don't get it twice.  The third
  143. rule adds our host name to the beginning.
  144.  
  145. S13 says that this is the beginning of a new rule set, number 13.
  146.  
  147. R$+<@$-.UUCP>        $2!$1                u@host.UUCP => host!u
  148.  
  149. R says that this is a rule.  The thing immediately after it,
  150. $+<@$-.UUCP> is a pattern.  If this pattern matches the address, then
  151. the rule "triggers".  If the rule triggers, the address is replaced
  152. with the "right hand side", i.e. what is after the tab(s).  In this
  153. rule, the right hand sie is $2!$1.  The thing after the next tab(s) is
  154. a comment.  This rule is used in processing UUCP addresses.  As noted
  155. above, by the time we get to it, rule 3 has already been applied.  So
  156. if we had a UUCP address of the form host1!host2!user, it would now be
  157. in the form host2!user<@host1.UUCP>.  This does match the pattern:
  158.  
  159.     $+      <@$-   .UUCP>   
  160.         host2!user<@host1.UUCP>
  161.  
  162. $+ and $- are "wildcards" that match anything.  $- will match exactly
  163. one word, while $+ will match any number.  (By the way, with the
  164. increasing use of domains, this production should probably use
  165. $+.UUCP, not $-.UUCP.)  Since the pattern matches, we replace this
  166. with the "right hand side" of the rule, $2!$1.  $ followed by a digit
  167. means the Nth thing matched by a wildcard.  In this case there were
  168. two wildcards, so
  169.    $1 = host2!user
  170.    $2 = host1
  171. The final result is 
  172.    host1!host2!user
  173. As you can see, we have simply turned UUCP addresses from the format
  174. produced by rule 3 back into normal ! format.
  175.  
  176. The second rule is
  177.  
  178. R$=U!$+            $2                strip local name
  179.  
  180. This is needed because there are situations in which our host name
  181. ends up on the beginning of the recipient address.  Since we are
  182. about to add our host name, we don't want it to be there twice.
  183. So if it was there before, we remove it.  $= is used to see if
  184. something is a member of a specified "class".  U happens to be a list
  185. of our UUCP host name and any nicknames.  So $=U!$+ matches
  186. any address that begins with our host name or nickname, then !, then
  187. anything else.  Suppose we had  topaz!host1!host2!user.  The
  188. match would be
  189.  
  190.      $=U  !$+
  191.      topaz!host1!host2!user
  192.  
  193. The result of the match is that
  194.  
  195.      $1 = topaz
  196.      $2 = host1!host2!user
  197.  
  198. Since the right hand side of this rule is simply "$2", the result is
  199.  
  200.      host1!host2!user
  201.  
  202. I.e. we have removed the topaz from the beginning.  By the way, the
  203. class U used by the rule would have been defined earlier in the file
  204. by the statement
  205.  
  206. CUtopaz ru-topaz
  207.  
  208. C defines a class.  U is the name of the class.  The rest of the
  209. line is the list of things that will be in the class.
  210.  
  211. Finally we have the rule
  212.  
  213. R$+            $:$U!$1                stick on our host name
  214.  
  215. The $+ matches anything.  In this case the name is host1!host2!user, so the
  216. result of the match is
  217.  
  218.     $1 = host1!host2!user
  219.  
  220. The result looks slightly obscure.  $: is a tag that says to do this
  221. only once.  The problem is that this rule always applies, since the
  222. pattern matches anything.  Normally, rules are applied over and
  223. over, as long as they apply.  In this case, the result would be
  224. an infinite loop.  Putting $: at the beginning says to do it only
  225. once.  $U says to use the value of the macro U.  Earlier in the
  226. file we defined U as our UUCP host name, with a definition
  227.  
  228. DUtopaz
  229.  
  230. Note that there can be a class and a macro with the same name.
  231. $=U tests whether something is in the class U.  $U is replaced
  232. by the value of the macro U.
  233.  
  234. So the final value of this rule, $:$U!$1, is
  235.  
  236.      topaz!host1!host2!user
  237.  
  238. So this rule has managed to add our host name to the beginning, as it
  239. was supposed to.  Since there are no further rules in the set (the
  240. next line is the end of file or the beginning of a new rule set),
  241. this value is returned.
  242.  
  243. There are several more magic things that can appear in a pattern.
  244. The most important are:
  245.  
  246. $* - this is another wild card.  It is similar to $+, but $+ matches
  247. anything, whereas $* matches both anything and nothing.  I.e. $+
  248. matches 1 or more tokens and $* matches 0 or more tokens.  So here
  249. is a list of the wildcards I have mentioned:
  250.  
  251.    $*   0 or more
  252.    $+   1 or more
  253.    $-   exactly 1
  254.    $=x  any member of class x
  255.  
  256. A typical example of $* is a production where we aren't sure whether
  257. the user name is before or after the host name:
  258.  
  259. R$*<@$+.UUCP>$*        $@$1<@$2.UUCP>$3
  260.  
  261. This production would test for the host name ending in .UUCP, and
  262. return immediately.  $@ is a flag you haven't seen yet.  It is simply
  263. a return statement.  It causes the right hand side of this rule to be
  264. returned as the final value of this rule set.
  265.  
  266. The other magic thing I will mention is $>.  This is a subroutine
  267. call.  Here is an example taken from rule set 24, which is used to
  268. process recipients in TCP mail.  Its purpose is to handle the
  269. situation where we might have an address like topaz!user@red.  (Our
  270. host name is topaz.  Red is a local host that we talk to via TCP.)
  271. I.e. someone is asking us to relay mail to red.  Rule 3 will have
  272. turned this into user@red<@topaz.UUCP>.  What we want to do is
  273. get rid of the topaz.UUCP and treat red as the host.  (Rule set 0
  274. would do this for the recipient on the envelope.  This rule is
  275. used for the to: field in the header.)  Here is the rule.
  276.  
  277. R$+<@$=U.UUCP>        $@$>9$1                in case local!a@b
  278.  
  279. The pattern matches our example, as follows:
  280.  
  281.    $+      <@$=U  .UUCP>
  282.    user@red<@topaz.UUCP>
  283.  
  284. Recall that $+ matches anything and $=U tests whether something is our
  285. UUCP host name or one of our nicknames.  The result of the match is
  286.  
  287.    $1 = user@red
  288.    $2 = topaz
  289.  
  290. The right hand side is $@$>9$1.  The $@ is the tag saying to stop the
  291. rule set here and return this value.  $>9 is a subroutine call.  It
  292. says to take the right hand side, pass it to rule set 9, and then
  293. use the value of rule set 9.  The actual right hand side is simply
  294. $1, which in this case is user@red.  Here is rule set 9:
  295.  
  296. S9
  297. R$*<$*>$*        $1$2$3                defocus
  298. R$+            $:$>3$1                make canonical
  299. R$+            $@$>24$1            and do 24 again
  300.  
  301. The first rule simply removes < >.  It is sort of a quick and dirty
  302. version of rule 4.  In fact we have no < > left, since we have removed
  303. the <@topaz.UUCP>.  So this rule does not trigger.  (Now that I think
  304. about it, I suspect it is probably never going to trigger, and so is
  305. not needed.)  
  306.  
  307. The next rule is a simple subroutine call.  It matches anything ($+
  308. matches any 1 or more token).  The right hand side is $:$>3$1 The $:
  309. says to do it only once.  Since the rule matches anything, you need
  310. this, or you will have an infinite loop.  The $>3 says to call rule 3
  311. as a subroutine.  The $1 is the actual right hand side.  Since the
  312. left hand side matched the whole address, what this rule does is
  313. simply call rule set 3 on the whole address.  Recall that rule set 3
  314. basically locates the host name and puts < > around it.  So in this
  315. case the result is user<@red>.  As you can see, it was not enough to
  316. remove <@topaz.UUCP>.  That leaves us with no  host name.  We have to
  317. call rule 3 to find the current host name and put < > around it.
  318.  
  319. The last rule is really just a goto statement.  The pattern is $+,
  320. which matches anything, so it always triggers.  The right hand side is
  321. $@$>24$1.  The $@ is the return tag.  It says to stop this rule set
  322. and return that value.  $>24 says to call rule set 24.  The actual
  323. right hand side is $1, so we call rule set 24 with the whole address.
  324. If you recall, this ruleset (9) was called from the  middle of 24 when
  325. we found user@red<@topaz.UUCP>.  So what we have done is to change
  326. this into user<@red> and say to start rule set 24 over again.
  327.  
  328. I hope you have found this exposition useful.  As a final convenience,
  329. here is a "reference card" for reading rule sets.  Note that this
  330. contains only operators used by the rules.  There are plenty of
  331. other facilities used in the configuration section which I am
  332. not documenting here.  (I'd love to see someone produce a complete
  333. reference card.)
  334.  
  335. wildcards:
  336.    $*   0 or more tokens
  337.    $+   1 or more tokens
  338.    $-   exactly one token
  339.    $=x  member of class x (x must be a letter, lower/upper case distinct)
  340.    $~x  not a member of class x
  341.  
  342. macro values (usable in pattern or on right hand side)
  343.    $x    value of macro x (x must be a letter, lower/upper case distinct)
  344.     At least on the Pyramid, $x is replaced by the macro's value
  345.     when the sendmail.cf file is being read in.
  346.  
  347. on the right hand side:
  348.    $n    string matched by the Nth wildcard
  349.    $>n    call rule set N as a subroutine
  350.    $@   return
  351.    $:   only do this rule once
  352.  
  353. in rule 0, defining the return value
  354.    $#   protocol
  355.    $@   host
  356.    $:   user
  357.  
  358. Rutgers extensions, usable only on right hand side
  359.    $%n  take the string matched by the Nth wildcard, look it up in
  360.     /etc/hosts, and if found use the primary host name
  361.    $&x    use the current value of macro x.  x must be a letter.
  362.     upper and lower case are treated as distinct.
  363.  
  364.  
  365.